#include "Service.h"
#include <cassert>


thread_local int Service::curWorkerIndex_ = -1;
void Service::Init()
{
	if (wokers_.empty())
	{
		int hc = std::thread::hardware_concurrency() - 1;
		hc = hc < 3 ? 3 : hc;
		wokers_.reserve(hc);
		for (int i = 0; i < hc; i++)
		{
			std::thread thread(&Service::Worker, this, i);
			wokers_.push_back(std::move(thread));
		}
	}
}

void Service::AddTask(Task* task)
{
	if (task)
	{
		queue_.Push(std::move(task));
	}
}

void Service::AddTaskFront(Task* task)
{
	if (task)
	{
		queue_.PushFront(std::move(task));
	}
}

void Service::AddCompleteTask(Task* task)
{
	if (task)
	{
		completeQueue_.Push(std::move(task));
	}
}

bool Service::CancelById(unsigned int id)
{
	return queue_.EraseById(id);
}

void Service::CancelByOwner(void* owner)
{
	queue_.EraseByOwner(owner);
}

void Service::Tick(float dt)
{
	if (!nextFuncs_.empty())
	{
		for (auto& func : nextFuncs_)
		{
			func();
		}
		nextFuncs_.clear();
	}

	for (auto& func : tickFuncs_)
	{
		func(dt);
	}

	Task* task = completeQueue_.TryPop();
	while (task)
	{
		task->OnComplete();
		task = completeQueue_.TryPop();
	}
}

void Service::Shutdown()
{
	int size = wokers_.size();
	for (int i = 0; i < size; i++)
	{
		queue_.Push(nullptr);
	}
	for (int i = 0; i < size; i++)
	{
		wokers_[i].join();
	}
}

void Service::Worker(int index)
{
	curWorkerIndex_ = index;

	while (true)
	{
		Task* task = queue_.Pop();
		if (task)
		{
			if (task->OnSchedule())
			{
				AddCompleteTask(std::move(task));
			}
		}
		else
		{
			break;
		}
	}
}

Task* Service::GetNextTask()
{
	return queue_.Pop();
}

void Service::PerformInMainThread(const std::function<void()>& func)
{
	auto task = new SimpleTask();
	task->SetCompleteFunction(func);
	AddCompleteTask(std::move(task));
}

void Service::PerformInNextLoop(const std::function<void()>& func)
{
	auto task = new SimpleTask();
	task->SetCompleteFunction([this, func]() {
		nextFuncs_.push_back(func);
	});
	AddCompleteTask(std::move(task));
}

void Service::AddTickFunction(const std::function<void(float)>& func)
{
	tickFuncs_.push_back(func);
}

void Service::PerformAsyn(const std::function<void()>& fun)
{
	auto task = new AsynSimpleTask();
	task->SetAsynFunction(fun);
	AddTask(task);
}



